﻿using Kimd.Common;
using Kimd.Communication;
using Kimd.Motion;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Serialization;

namespace Kimd.Machine
{
    [Serializable]
    public class MachineResource : SingletonProvider<MachineResource>
    {
        private System.Threading.Thread monitorTask;
        private object _lockObj;
        private object _saveObj;
        public List<string> CardConfig { get; set; }
        public SerializableDictionary<string, ControlCard> MachineCard { get; set; }
        public SerializableDictionary<string, Axis> MachineAxis { get; set; }
        public SerializableDictionary<string, Coordinate2D> MachineCoordinates { get; set; }
        public SerializableDictionary<string, Sensor> MachineSensor { get; set; }
        public SerializableDictionary<string, Cylinder> MachineCylinder { get; set; }
        public SerializableDictionary<string, Pdo> MachinePdo { get; set; }
        public SerializableDictionary<string, SerialPortHelper> MachineSerialPort { get; set; }
        public SerializableDictionary<string, TCPClient> MachineTcpClient { get; set; }
        public SerializableDictionary<string, TCPServer> MachineTcpServer { get; set; }
        public SerializableDictionary<string, ModbusTcp> MachineModbusTcp { get; set; }
        public SerializableDictionary<string, PLCOperator> MachinePLC { get; set; }
        public SerializableDictionary<string, SerializableDictionary<string, PointPath>> ModulePaths { get; set; }
        public SerializableDictionary<string, SerializableDictionary<string, Tray>> ModuleTrays { get; set; }
        [XmlIgnore]
        public Dictionary<string, Form> MachineUI { get; set; }
        public MachineResource()
        {
            _lockObj = new object();
            _saveObj = new object();

            MachineCoordinates = new SerializableDictionary<string, Coordinate2D>();
            MachineCard = new SerializableDictionary<string, ControlCard>();
            MachineAxis = new SerializableDictionary<string, Axis>();
            MachineSensor = new SerializableDictionary<string, Sensor>();
            MachineCylinder = new SerializableDictionary<string, Cylinder>();
            MachinePdo = new SerializableDictionary<string, Pdo>();
            ModulePaths = new SerializableDictionary<string, SerializableDictionary<string, PointPath>>();
            ModuleTrays = new SerializableDictionary<string, SerializableDictionary<string, Tray>>();
            MachineTcpClient = new SerializableDictionary<string, TCPClient>();
            MachineTcpServer = new SerializableDictionary<string, TCPServer>();
            MachineModbusTcp = new SerializableDictionary<string, ModbusTcp>();
            MachinePLC = new SerializableDictionary<string, PLCOperator>();
        }
        public object GetLockObject()
        {
            return _lockObj;
        }
        //精定位下层移栽气缸的移动条件
        private (bool,string) check()
        {
            if (!MachineResource.Instance.MachineSensor["精定位1扫码升降气缸原点"].WaitOn())
            {
                return (false, "扫码升降气缸不在下位，无法移动气缸");
            }
            if ((MachineResource.Instance.MachineAxis["测试移载线1左轴"].IsNearPosition("Arm1精定位下层取料位置", 5) &&
                MachineResource.Instance.MachineAxis["Arm1Z轴"].IsGreaterThanPosition(MachineResource.Instance.MachineAxis["Arm1Z轴"].MotionPosition["待机位"])) ||
                (MachineResource.Instance.MachineAxis["测试移载线1右轴"].IsNearPosition("Arm2精定位下层取料位置", 5) &&
                MachineResource.Instance.MachineAxis["Arm2Z轴"].IsGreaterThanPosition(MachineResource.Instance.MachineAxis["Arm2Z轴"].MotionPosition["待机位"])))
            {
                return (false, "ArmZ轴不在安全位，无法移动气缸");
            }
            return (true,"");
        }
        private (bool, string) check2()
        {
            if (!MachineResource.Instance.MachineSensor["精定位2扫码升降气缸原点"].WaitOn())
            {
                return (false, "扫码升降气缸不在下位，无法移动气缸");
            }
            if ((MachineResource.Instance.MachineAxis["测试移载线2左轴"].IsNearPosition("Arm3精定位下层取料位置", 5) &&
                MachineResource.Instance.MachineAxis["Arm3Z轴"].IsGreaterThanPosition(MachineResource.Instance.MachineAxis["Arm3Z轴"].MotionPosition["待机位"])) ||
                (MachineResource.Instance.MachineAxis["测试移载线2右轴"].IsNearPosition("Arm4精定位下层取料位置", 5) &&
                MachineResource.Instance.MachineAxis["Arm4Z轴"].IsGreaterThanPosition(MachineResource.Instance.MachineAxis["Arm4Z轴"].MotionPosition["待机位"])))
            {
                return (false, "ArmZ轴不在安全位，无法移动气缸");
            }
            return (true, "");
        }
        private (bool, string) check3()
        {
            if ((MachineResource.Instance.MachineAxis["测试移载线1左轴"].IsNearPosition("Arm1精定位上层取料位置", 5) &&
                MachineResource.Instance.MachineAxis["Arm1Z轴"].IsGreaterThanPosition(MachineResource.Instance.MachineAxis["Arm1Z轴"].MotionPosition["待机位"])) ||
                (MachineResource.Instance.MachineAxis["测试移载线1右轴"].IsNearPosition("Arm2精定位上层取料位置", 5) &&
                MachineResource.Instance.MachineAxis["Arm2Z轴"].IsGreaterThanPosition(MachineResource.Instance.MachineAxis["Arm2Z轴"].MotionPosition["待机位"])))
            {
                return (false, "ArmZ轴不在安全位，无法移动气缸");
            }
            return (true, "");
        }
        private (bool, string) check4()
        {
            if ((MachineResource.Instance.MachineAxis["测试移载线2左轴"].IsNearPosition("Arm3精定位上层取料位置", 5) &&
                MachineResource.Instance.MachineAxis["Arm3Z轴"].IsGreaterThanPosition(MachineResource.Instance.MachineAxis["Arm3Z轴"].MotionPosition["待机位"])) ||
                (MachineResource.Instance.MachineAxis["测试移载线2右轴"].IsNearPosition("Arm4精定位上层取料位置", 5) &&
                MachineResource.Instance.MachineAxis["Arm4Z轴"].IsGreaterThanPosition(MachineResource.Instance.MachineAxis["Arm4Z轴"].MotionPosition["待机位"])))
            {
                return (false, "ArmZ轴不在安全位，无法移动气缸");
            }
            return (true, "");
        }
        private (bool, string) check5()
        {
            if ((MachineResource.Instance.MachineAxis["测试移载线1左轴"].IsNearPosition("Arm1精定位上层取料位置", 5) &&
                MachineResource.Instance.MachineAxis["Arm1Z轴"].IsGreaterThanPosition(MachineResource.Instance.MachineAxis["Arm1Z轴"].MotionPosition["待机位"])) ||
                (MachineResource.Instance.MachineAxis["测试移载线1右轴"].IsNearPosition("Arm2精定位上层取料位置", 5) &&
                MachineResource.Instance.MachineAxis["Arm2Z轴"].IsGreaterThanPosition(MachineResource.Instance.MachineAxis["Arm2Z轴"].MotionPosition["待机位"])))
            {
                return (false, "ArmZ轴不在安全位，无法移动气缸");
            }
            return (true, "");
        }
        public void StartMonitor()
        {
            MotionLimit.MachineAxis = this.MachineAxis;
            MotionLimit.MachineSensor = this.MachineSensor;

            //MachineResource.Instance.MachineCylinder["精定位1下层移载气缸"].PreCheckOff = check;
            //MachineResource.Instance.MachineCylinder["精定位2下层移载气缸"].PreCheckOff = check2;
            //MachineResource.Instance.MachineCylinder["精定位1上层移载气缸"].PreCheckOff = check3;
            //MachineResource.Instance.MachineCylinder["精定位2上层移载气缸"].PreCheckOff = check4;
            //MachineResource.Instance.MachineCylinder["精定位1NG料移载气缸"].PreCheckOn = check5;

            monitorTask = new System.Threading.Thread(() =>
            {
                string errInfo = "";

                while (true)
                {
                    lock (_lockObj)
                    {
                        foreach (Axis axis in MachineAxis.Values)
                        {
                            if (axis.PositionLimits != null && axis.PositionLimits.Count > 0)
                            {
                                for (int i = 0; i < axis.PositionLimits.Count; i++)
                                {
                                    if (axis.PositionLimits[i].IsEnable)
                                    {
                                        if (axis.PositionLimits[i].IsBreakRule(axis.CurrentDirection, out errInfo))
                                        {
                                            //条件未满足
                                            axis.Stop(false);
                                            //
                                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Error, string.Format("轴{0}位置限制触发!原因:{1}", axis.Description, errInfo), "Main", 0, "系统"));
                                        }
                                    }
                                }
                            }
                            if (axis.SensorLimits != null && axis.SensorLimits.Count > 0)
                            {
                                for (int i = 0; i < axis.SensorLimits.Count; i++)
                                {
                                    if (axis.SensorLimits[i].IsEnable)
                                    {
                                        if (axis.SensorLimits[i].IsBreakRule(axis.CurrentDirection, out errInfo))
                                        {
                                            //条件未满足
                                            axis.Stop(false);
                                            //
                                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Error, string.Format("轴{0}感应器限制触发!原因:{1}", axis.Description, errInfo), "Main", 0, "系统"));
                                        }
                                    }
                                }
                            }
                        }
                    }
#if DEBUGWITHOUTMACHINE
#else
                    foreach (ControlCard card in MachineCard.Values)
                    {
                        if(card.IsErr)
                        {
                            MachineMessageScheduler.Instance.Add(new MachineMessage(MessageType.Error, string.Format("卡{0}Api调用异常", card.Description), "Main", 0, "系统"));
                            foreach (Axis axis in MachineAxis.Values)
                            {
                                axis.Stop(false);
                            }
                        }
                    }
#endif

                    System.Threading.Thread.Sleep(20);
                }
            });
            monitorTask.IsBackground = true;
            monitorTask.Start();
        }
        public void StopMonitor()
        {
            if(monitorTask != null) 
            { 
                monitorTask.Abort(); 
            }
        }
        public void AddAxis(string name, Axis axis)
        {
            this.MachineAxis.Add(name, axis);
        }
        public void RemoveAxis(string name)
        {
            this.MachineAxis.Remove(name);
        }
        public void AddCylinder(string name, Cylinder cylinder)
        {
            this.MachineCylinder.Add(name, cylinder);
        }
        public void RemoveCylinder(string name)
        {
            this.MachineCylinder.Remove(name);
        }
        public void AddSensor(string name, Sensor sensor)
        {
            this.MachineSensor.Add(name, sensor);
        }
        public void RemoveSensor(string name)
        {
            this.MachineSensor.Remove(name);
        }
        public void Save(string configName)
        {
            lock (_saveObj)
            {
                bool isSuccess = false;
                try
                {
                    XmlSerializerHelper<MachineResource>.SerializeToFile(SingletonProvider<MachineResource>.Instance, PathHelper.GetConfigPath("Machine") + "backup.xml");
                    isSuccess = true;
                }
                catch (Exception ex)
                {
                    LogHelper.Instance.Log("system", ex.Message, MessageLevel.Log);
                }
                if (isSuccess)
                {
                    XmlSerializerHelper<MachineResource>.SerializeToFile(SingletonProvider<MachineResource>.Instance, PathHelper.GetConfigPath("Machine") + configName);
                }
            }
        }
    
        public List<string> GetAllModuleNames()
        {
            List<string> moduleNames = new List<string>();
            foreach (var item in MachineAxis.Values)
            {
                if (!moduleNames.Contains(item.Module))
                    moduleNames.Add(item.Module);
            }
            foreach (var item in MachineSensor.Values)
            {
                if (!moduleNames.Contains(item.Module))
                    moduleNames.Add(item.Module);
            }
            foreach (var item in MachineCylinder.Values)
            {
                if (!moduleNames.Contains(item.Module))
                    moduleNames.Add(item.Module);
            }
            return moduleNames;
        }
    }
}
